﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NLog;
using System.IO;
using LingDong.HtmlParser;
using System.Diagnostics;
using LingDong.IndexReader;
using LingDong.PictureKeywords;

namespace LingDong.PictureKeywordsExample
{
    class NewExperiment
    {
        #region Candidate Result

        internal static void CreateCandidateResult()
        {
            using (StreamReader sr = new StreamReader(standardKeywordsInputFile))
            using (StreamWriter sw = new StreamWriter(candidateResultOutputFile))
            {
                while (!sr.EndOfStream)
                {
                    string line = sr.ReadLine();
                    string[] terms = sr.ReadLine().Split(new string[] { " ", "\t" }, StringSplitOptions.RemoveEmptyEntries);
                    sr.ReadLine();

                    OutputCandidateFile(line, terms, sw);
                }
            }
        }

        private static void OutputCandidateFile(string line, string[] terms, StreamWriter sw)
        {
            string file = line.Split()[0];
            string content = HtmlContent.GetHtmlContentByFilePath(file);
            string[] sentenceList = content.Split(ConfigProvider.SentenceSplitter.Get(),
                                                  StringSplitOptions.RemoveEmptyEntries).
                                                  Select(sen => sen.Trim()).Distinct().ToArray();

            sw.WriteLine(line);
            foreach (string sen in sentenceList)
            {
                if (sen.Length < 10)
                    continue;

                foreach (string term in terms)
                {
                    if (sen.Contains(term))
                    {
                        sw.Write(sen);
                        sw.Write('\t');
                        break;
                    }
                }
            }
            sw.WriteLine();
            sw.WriteLine();
        }

        #endregion


        #region Visibility Result
        
        internal static void VisibilityResult()
        {
            Dictionary<string, List<string>> candidateResult = ReadResult(candidateResultOutputFile);
            Dictionary<string, List<string>> visibilityKeywords = ReadResult(visibilityInputFile);
            Debug.Assert(candidateResult.Count() == visibilityKeywords.Count());

            using (StreamWriter sw = new StreamWriter(visibilityResultFile))
            using (Index index = new Index())
            {
                foreach (string line in candidateResult.Keys)
                {
                    List<string> senList = candidateResult[line];
                    List<string> wordList = visibilityKeywords[line];
                    OperatorOneDoc(line, senList, wordList, index, sw);
                }
            }
        }

        private static void OperatorOneDoc(string line, List<string> senList, List<string> wordList, Index index, StreamWriter sw)
        {
            Dictionary<string, double> topSentence = new Dictionary<string, double>();
            foreach (string sen in senList)
            {
                double score = GetScore(sen, wordList, index);
                topSentence.Add(sen, score);
            }

            List<KeyValuePair<string, double>> topSenOrdered = (from d in topSentence orderby d.Value descending select d).
                                                                Take(10).
                                                                ToList();
            sw.WriteLine(line);
            foreach (KeyValuePair<string, double> pair in topSenOrdered)
            {
                sw.Write(pair.Key);
                sw.Write("\t");
            }
            sw.WriteLine();
            sw.WriteLine();
        }

        private static double GetScore(string sen, List<string> wordList, Index index)
        {
            double dis = 1.0;
            double pos = 1.0;

            double score = 0.0;
            foreach (string word in wordList)
            {
                int tf = GetSubStringNum(sen, word);
                double idf = 1.0 / (double)index.GetTermDocumentFrequency(word);
                score += idf * tf / dis * pos;
            }
            return score;
        }

        private static Dictionary<string, List<string>> ReadResult(string inputFileName)
        {
            Dictionary<string, List<string>> result = new Dictionary<string, List<string>>();
            using (StreamReader sr = new StreamReader(inputFileName))
            {
                while (!sr.EndOfStream)
                {
                    string line = sr.ReadLine();
                    List<string> terms = sr.ReadLine().Split(new string[] { " ", "\t" }, StringSplitOptions.RemoveEmptyEntries).ToList();
                    result.Add(line, terms);
                    sr.ReadLine();
                }
            }
            return result;
        }

        #endregion


        #region PR

        internal static void ComputePR()
        {
            KeyValuePair<double, double> result = Assessment.Run(standardKeywordsInputFile, visibilityInputFile);
            logger.Debug("Precision\tRecall");
            logger.Debug(String.Format("{0}%\t{1}%", Math.Round(result.Key * 100, 2), Math.Round(result.Value * 100, 2)));
        }

        #endregion


        #region Run Experiment2

        internal static void RunExperiment2()
        {
            RunTest(visibilityResultFile);
            RunTest(DOMTreeOutputFile);
            RunTest(VIPSOutputFile);
        }

        private static void RunTest(string programResultFile)
        {
            KeyValuePair<double, double> result = Assessment.Run(standardResultFile, programResultFile);
            double F = Assessment.GetF(result.Key, result.Value);

            double S = GetQScore(programResultFile);

            logger.Debug("Precision\tRecall\tF\tQScore");
            logger.Debug(String.Format("{0}%\t{1}%\t{2}\t{3}", 
                Math.Round(result.Key * 100, 2), 
                Math.Round(result.Value * 100, 2),
                Math.Round(F * 100, 4),
                Math.Round(S, 4)));
        }

        private static double GetQScore(string programResultFile)
        {
            Dictionary<string, List<string>> keywords = ReadResult(standardKeywordsInputFile);
            Dictionary<string, List<string>> programResult = ReadResult(programResultFile);
            Debug.Assert(keywords.Count == programResult.Count);

            List<double> qScore = new List<double>();
            foreach (string line in programResult.Keys)
            {
                double q = GetSinglePageQScore(programResult[line], keywords[line], line);
                qScore.Add(q);
            }
            return qScore.Average();
        }

        private static double GetSinglePageQScore(List<string> programResultList, List<string> keywords, string line)
        {
            string filename = line.Split()[0];
            double result = 0.0;
            double[] alpha = new double[] { 2, 2, 2, 2, 2 };
            for (int i = 0; i < 5; i++)
            {
                string key = keywords[i];
                int ks = GetSubStringNum(programResultList, key);
                int kp = GetOriPageAppearNum(filename, key);
                result += (double)ks / kp * alpha[i];
            }
            return result;
        }

        private static int GetOriPageAppearNum(string filename, string key)
        {
            string content;
            string code = filename.Contains("ifeng") ? "UTF-8" : "GB2312";
            Encoding encode = Encoding.GetEncoding(code);
            using (StreamReader sr = new StreamReader(filename, encode))
            {
                content = sr.ReadToEnd();
            }
            return GetSubStringNum(content, key);
        }

        private static int GetSubStringNum(List<string> programResultList, string key)
        {
            StringBuilder content = new StringBuilder();
            foreach (string s in programResultList)
            {
                content.Append(s);
            }
            return GetSubStringNum(content.ToString(), key);
        }

        private static int GetSubStringNum(string str, string sub)
        {
            return str.Replace("#", "").Replace(sub, "#").Count(c => c == '#');
        }

        #endregion

        #region Private Members

        private static string inputDir = @"F:\LingDongData\WebPage\TestExple\";
        private static string indexFile = @"F:\LingDongData\WebPage\index.txt";

        private static string standardKeywordsInputFile = @"F:\LingDongData\WebPage\standard_keywords.txt";
        private static string candidateResultOutputFile = @"F:\LingDongData\WebPage\candidate_result.txt";
        private static string visibilityResultFile = @"F:\LingDongData\WebPage\visibility_result.txt";
        private static string standardResultFile = @"F:\LingDongData\WebPage\standard_result.txt";

        private static string visibilityInputFile = @"F:\LingDongData\WebPage\visibility_keywords.txt";
        private static string DOMTreeOutputFile = @"F:\LingDongData\WebPage\DOMTree_result.txt";
        private static string VIPSOutputFile = @"F:\LingDongData\WebPage\VIPS_result.txt";

        private static string visibilityCountOutputFile = @"F:\LingDongData\WebPage\visibility_count.txt";
        private static string pictureIndexFile = @"F:\LingDongData\WebPage\pic_index.txt";

        private static Logger logger = LogManager.GetCurrentClassLogger();

        #endregion
    }
}
